/**
 * @file filter
 * @author liaoxuezhi@baidu.com
 */
/* eslint fecs-indent: [0, "space", 2, 2] */

import * as React from 'react';
import {
  PureComponent,
  PropTypes
} from 'react';
import {Renderer, padArr} from '../../renderer';
import * as cx from 'classnames';
import {filterOptions} from '../util';
import {Enhance as FormItem} from '../form-item';

@FormItem({
  type: 'checkboxs',
  test: (path, config) => /(?:^|\/)form-item$/.test(path) && (config.type === 'checkboxes' || config.type === 'radios'),
  validateSchema: 'http://amis.baidu.com/schemas/form.json#/definitions/formItem'
})

export default class FormCheckboxes extends PureComponent {
  static propTypes = {
    className: PropTypes.string,
    formMode: PropTypes.string,
    formHorizontal: PropTypes.object,
    options: PropTypes.oneOfType([
      PropTypes.array,
      PropTypes.string
    ]),
    joinValues: PropTypes.bool.isRequired,
    delimiter: PropTypes.string.isRequired,
    checkAll: PropTypes.bool,
    checkAllLabel: PropTypes.string,
    defaultCheckAll: PropTypes.bool
  };

  static defaultProps = {
    value: '',
    joinValues: true,
    delimiter: ',',
    options: [],
    columnsCount: 1,
    checkAll: false,
    checkAllLabel: '全选',
    defaultCheckAll: false,
    addable: false
  };

  static contextTypes = {
    combo: PropTypes.object
  };

  multiple = true;

  constructor(props) {
    super(props);
    const options = props.sourceLocalData ? filterOptions(props.sourceLocalData, props.data) : (filterOptions(props.options, props.data) || [])

    this.state = {
      options: options,
      checkAll: props.defaultCheckAll
    };

    this.changeValue = this.changeValue.bind(this);
    this.toggleCheckAll = this.toggleCheckAll.bind(this);
    this.buildCheckAll = this.buildCheckAll.bind(this);
    this.addText = this.addText.bind(this);
  }

  componentWillMount() {
    const {
      unique,
      name,
      source,
      sourceLocalData
    } = this.props;
    const combo = this.context.combo;
    if (unique && combo && (sourceLocalData || !source)) {
      combo.registerUnique(name, this);
      this.setState({
        options: combo.getRestOptions(name, this)
      });
    }

    this.buildCheckAll();
    const defaultCheckAll = this.props.defaultCheckAll;

    if (defaultCheckAll) {
      this.toggleCheckAll(null, true);
    }
  }

  componentWillReceiveProps(nextProps) {
    const props = this.props;
    const defaultCheckAll = nextProps.defaultCheckAll;
    const combo = this.context.combo;
    if (props.sourceFetching && !nextProps.sourceFetching && nextProps.sourceData) {
      const sourceData = nextProps.sourceData;
      let options = filterOptions(sourceData && sourceData.hasOwnProperty('options') ? sourceData.options : sourceData, nextProps.data);

      if (nextProps.unique && combo) {
        combo.registerUnique(nextProps.name, this, options);
        options = combo.getRestOptions(nextProps.name, this);
      }

      this.setState({
        rawOptions: sourceData && sourceData.hasOwnProperty('options') ? sourceData.options : sourceData,
        options: options,
        checkAll: nextProps.defaultCheckAll
      }, _=>{
        sourceData.hasOwnProperty('value') && this.props.setValue(sourceData.value);
        defaultCheckAll && this.toggleCheckAll(null, true);
      });
    }

    if (props.options !== nextProps.options || props.sourceLocalData !== nextProps.sourceLocalData) {
      let options = filterOptions(nextProps.sourceLocalData || nextProps.options, nextProps.data) || [];

      if (nextProps.unique && combo) {
        combo.registerUnique(nextProps.name, this, options);
        options = combo.getRestOptions(nextProps.name, this);
      }

      this.setState({
        options: options,
        checkAll: nextProps.defaultCheckAll
      }, _=> {defaultCheckAll && this.toggleCheckAll(null, true)});
    }
    // else if (props.data !== nextProps.data && nextProps.unique && combo) {
    //   let options = filterOptions(this.state.rawOptions || nextProps.sourceLocalData || nextProps.options, nextProps.data) || [];
    
    //   if (nextProps.unique && combo) {
    //     combo.registerUnique(nextProps.name, this, options);
    //     options = combo.getRestOptions(nextProps.name, this, true);
    //   }
    
    //   this.setState({
    //     options: options,
    //     checkAll: nextProps.defaultCheckAll
    //   });
    // }

    this.buildCheckAll();
  }

  componentWillUnmount() {
    const {
      unique,
      name
    } = this.props;
    const combo = this.context.combo;

    if (unique && combo) {
      combo.unRegisterUnique(name, this);
    }
  }

  changeValue(option, checked) {
    let value = this.props.getValue();
    const {
      joinValues,
      delimiter
    } = this.props;

    if (joinValues) {
      value = String(value).split(delimiter);
    } else if (!value) {
      value = [];
    }

    const checkedMap = {};
    const type = this.props.type;

    if (type === 'checkboxes') {
      value.forEach(item => checkedMap[joinValues ? item : item.value] = true);
    }

    checkedMap[option.value] = checked;
    const options = this.state.options;

    value = options.filter(option => checkedMap[option.value]);

    if (joinValues && type === 'checkboxes' || type === 'radios') {
      value = value.map(item => item.value).join(delimiter);
    }

    this.props.setValue(value);
    this.props.onChange && this.props.onChange(value);
    this.buildCheckAll();
  }

  buildCheckAll() {
    const {
      joinValues,
      delimiter,
      type
    } = this.props;
    if(type != 'checkboxes') {
      return;
    }
    const options = this.state.options;
    let value = this.props.getValue() || (joinValues ? '' : []);
    if (joinValues && typeof value === 'string') {
      value = !value ? [] : value.split(delimiter);
    }

    this.setState({
      checkAll: value.length === options.length
    });
  }

  toggleCheckAll(e, checkAll) {
    const {
      joinValues,
      delimiter,
      type
    } = this.props;
    if(type != 'checkboxes') {
      return;
    }
    checkAll = checkAll === void 0 ? this.state.checkAll : !checkAll;
    let value = [];
    if (!checkAll) {
      const options = this.state.options;
      value = options.concat();
    }
    if (joinValues) {
      value = value.map(item => item.value).join(delimiter);
    }

    this.props.setValue(value);
    this.props.onChange && this.props.onChange(value);
    this.setState({
      checkAll: !this.state.checkAll
    });
    this.buildCheckAll();
  }

  addText(evt) {
    const {
      defaultCheckAll
    } = this.props;

    if(evt.keyCode == 13) {
      evt.preventDefault();
      const value = evt.target.value;
      let options = this.state.options;

      options = options.concat({label: value, value: value});
      evt.target.value = '';
      this.setState({options}, () => {defaultCheckAll && this.toggleCheckAll(null, true)});
      this.buildCheckAll();
    }
  }

  render() {
    const {
      label,
      type,
      joinValues,
      delimiter,
      placeholder,
      inline,
      inputClassName,
      checkAll,
      checkAllLabel,
      addable,
      disabled,
      addClassName
    } = this.props;

    const options = this.state.options.concat();
    let columnsCount = this.props.columnsCount;
    columnsCount = parseInt(columnsCount, 10) || 1;

    const checked = {};
    let value = this.props.getValue();
    value = typeof value === 'number' ? String(value) : value;

    if (options && options.length > 0 && checkAll && type === 'checkboxes') {
      options.unshift({
        label: checkAllLabel,
        value: '-1'
      });
    }

    if (type === 'checkboxes') {
      (joinValues ? String(value).split(delimiter) : (value || [])).forEach(value => checked[joinValues ? value : value.value] = true);
    } else if (value && type === 'radios') {
      checked[value] = true;
    }

    let body = [
    ];

    if (!options || !options.length) {
      body.push(
        <p key="placeholder" className="placeholder">{placeholder}</p>
      );
    } else if (columnsCount > 1) {
      padArr(options, columnsCount).forEach((options, key) => {
        body.push(
          <div className="row" key={key}>
            {options.map((option, index) => {
              const disabled = this.props.isFormDisabled() || this.props.disabled || option.disabled;

              return (
                <div key={index} className={`col-sm-${Math.floor(12 / columnsCount)}`}>
                  <div
                    className={cx(`${type === 'radios' ? 'radio' : 'checkbox'}${inline ? '-inline' : ''}`, {
                      'text-muted': disabled
                    })}
                  >
                    <label className="i-checks">
                      <input
                        type={type === 'radios' ? 'radio' : 'checkbox'}
                        checked={key == 0 && index == 0 && checkAll && type == 'checkboxes' ? this.state.checkAll : !!checked[option.value]}
                        onChange={key == 0 && index == 0 && checkAll && type == 'checkboxes' ? this.toggleCheckAll : (e => this.changeValue(option, e.currentTarget.checked))}
                        disabled={disabled}
                      />
                      <i />
                      {option.label}
                    </label>
                  </div>
                </div>
              )
            })}
          </div>
        );
      });
    } else {
      options.forEach((option, index) => {
        const disabled = this.props.isFormDisabled() || this.props.disabled || option.disabled;
        body.push(
          <div
            key={`checkbox-${index}`}
            className={`${type === 'radios' ? 'radio' : 'checkbox'}${inline ? '-inline' : ''}`}
          >
            <label
              className={cx('i-checks', {
                'text-muted': disabled
              })}
            >
              <input
                type={type === 'radios' ? 'radio' : 'checkbox'}
                checked={index == 0 && checkAll && type == 'checkboxes' ? this.state.checkAll : !!checked[option.value]}
                onChange={index == 0 && checkAll && type == 'checkboxes' ? this.toggleCheckAll : (e => this.changeValue(option, e.currentTarget.checked))}
                disabled={disabled}
              />
              <i />
              {option.label}
            </label>
          </div>
        );
      });
    }

    if (addable) {
      let addElement = (
        <div
          key='addText'
          className={`${type === 'radios' ? 'radio' : 'checkbox'}${inline ? '-inline' : ''}`}
        >
          <input
            type="text"
            className={cx('form-control', addClassName)}
            onKeyDown={this.addText}
            placeholder="请输入以增加更多"
            disabled={disabled}
          />
        </div>
      );

      if (columnsCount > 1) {
        addElement = (
          <div className={`col-sm-${Math.floor(12 / columnsCount)}`}>
            {addElement}
          </div>
        );
      }
      body.push(addElement);
    }

    return (
      <div
        className={cx(inputClassName, {
          "inline-checkboxes-control": inline
        })}
      >
        {body}
      </div>
    );
  }
}
